<?php
namespace PsiFramework\Classes\Util\Security\DAO;

import("Classes.DAO.AbstractDAO");
import("Classes.Util.Security.Model.SecurityRight");

use \PsiFramework\Classes\DAO\AbstractDAO;
use \PsiFramework\Classes\Factory\DAOFactory;
use \PsiFramework\Classes\Model\Object;
use \PsiFramework\Classes\Util\Database\Filters\QueryFilter;
use \PsiFramework\Classes\Util\Database\Query\SqlColumn;
use \PsiFramework\Classes\Util\Database\Query\SqlOperation;
use \PsiFramework\Classes\Util\Database\Query\SqlValue;
use \PsiFramework\Classes\Util\Security\Model\SecurityRight;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */

/**
 * Classe de DAO pour les droits
 *
 * @package Classes.Util.Security.DAO
 */
class SecurityRightDAO extends AbstractDAO
{
     
    protected static $_singleton = null;

    public function getRightsForUserWithRoles(
        Object    $user=null,
        /*array*/ $roleIds=array()
    )
    {
        $userId = 0 ;
        if (!is_null($user)) {
            $userId = $user->getId();
        }

        $colUser = new SqlColumn("user_id");
        $colRole = new SqlColumn("role_id");

        $or = new SqlOperation(SqlOperation::$or);
        if ($userId != 0 && !is_null($userId)) {
            $or->addParameter(
                $this->getOperationForUserOrRole(
                    $colUser,
                    array($userId)
                )
            );
        }

        $and = new SqlOperation(SqlOperation::$and);
        $and->addParameter($this->getOperationForUserOrRoleWhereNull($colRole));
        $and->addParameter($this->getOperationForUserOrRoleWhereNull($colUser));

        $or->addParameter($and);

        $globalOr = new SqlOperation(SqlOperation::$or);
        $globalOr->addParameter($or);

        if (!is_null($roleIds) && count($roleIds)>0) {
            $globalOr->addParameter(
                $this->getRightsForRoleOperation(
                    $colRole,
                    $colUser,
                    $roleIds
                )
            );
        }

        return $this->retrieveAll(new QueryFilter($globalOr), null, false);
    }

    /**
     * Returns the security rights for the user
     *
     * @param     User    $user    The user
     * @return    SecurityRight[]
     */
    public function getRightsForUser(Object $user=null)
    {

        $roleIds = array();
        $roles= null ;
        if (!is_null($user)) {
            $roles = $user->getRoles();
        }

        if (!is_null($roles)) {
            foreach ($roles as $userRole) {
                $role = $userRole->getRole();
                $roleIds[] = $role->getId();
            }
        }

        return $this->getRightsForUserWithRoles($user, $roles);
    }

    /**
     * Returns the security rights for the user
     *
     * @param     User    $user    The user
     * @return    SecurityRight[]
     */
    public function getRightsForSessionUser(Object $user=null)
    {


        $roleIds = array();
        $roles= null ;
        if (!is_null($user)) {
            $roleDao = DAOFactory::getDAO("SecurityRole");
            $roles = $roleDao->getRolesForUser($user);
        }

        if (!is_null($roles)) {
            foreach ($roles as $role) {
                $roleIds[] = $role->getId();
            }
        }

        return $this->getRightsForUserWithRoles($user, $roleIds);
    }

    protected function getRightsForRoleOperation(
        SqlColumn $colRole,
        SqlColumn $colUser,
        $roleIds
    )
    {
        $or = $this->getOperationForUserOrRole($colRole, $roleIds);

        $and = new SqlOperation(SqlOperation::$and);
        $and->addParameter($this->getOperationForUserOrRoleWhereNull($colRole));
        $and->addParameter($this->getOperationForUserOrRoleWhereNull($colUser));

        $globalOr = new SqlOperation(SqlOperation::$or);
        $globalOr->addParameter($or);
        $globalOr->addParameter($and);

        return $globalOr ;
    }

    /**
     * Returns the security rights for the role
     *
     * @param     SecurityRole    $role    The role
     * @return    SecurityRight[]
     */
    public function getRightsForRole(/*SecurityRole*/ $role=null)
    {

        $roleId = 0 ;
        if (!is_null($role)) {
            $roleId = $role->getId();
        }

        $colRole = new SqlColumn("role_id");
        $colUser = new SqlColumn("user_id");

        $globalOr = $this->getRightsForRoleOperation(
            $colRole,
            $colUser,
            array($roleId)
        );

        return $this->retrieveAll(new QueryFilter($globalOr), null, false);
    }

    protected function getOperationForUserOrRoleWhereNull(SqlColumn $col)
    {
        $equalZero = new SqlOperation(SqlOperation::$equal);
        $equalZero->addParameter($col);
        $equalZero->addParameter(new SqlValue(0));

        $isNull = new SqlOperation(SqlOperation::$isNull);
        $isNull->addParameter($col);

        $or = new SqlOperation(SqlOperation::$or);
        $or->addParameter($equalZero);
        $or->addParameter($isNull);

        return $or ;
    }

    protected function getOperationForUserOrRole(SqlColumn $col, $roleIds)
    {

        $or = new SqlOperation(SqlOperation::$or);
        foreach ($roleIds as $roleId) {
            $equal = new SqlOperation(SqlOperation::$equal);
            $equal->addParameter($col);
            $equal->addParameter(new SqlValue($roleId));
            $or->addParameter($equal);
        }

        return $or ;
    }

    /**
     * Function to be called instead of the constructor.
     *
     * @return SecurityRightDAO instance
     */
    public static function getInstance($objectParameters)
    {

        if (self::$_singleton==null) {
            self::$_singleton = new SecurityRightDAO($objectParameters);
        }

        return self::$_singleton;
    }
}
